//==============================================================================
// Copyright (c) 2008-2013 Niall Ryan. All Rights Reserved.
//==============================================================================

#ifndef HYDRA_ATOMIC_ATOMICPAIR_H
#define HYDRA_ATOMIC_ATOMICPAIR_H 1

#include "hydra/atomic/Atomic.h"

namespace Hydra
{
	/**
	 * Stores a pair of variables and treats them as an atomic unit. This is a convenience class, as the same
	 * effect could be achieved by putting the variables in a struct and using the Atomic wrapper. The combined
	 * size of the variables must be less than or equal to 8 bytes.
	 *
	 * A common use of this class is to combine a pointer and a stamp in an atomic unit.
	 */
	template<typename T, typename U>
	class AtomicPair
	{
	public:
		AtomicPair() { }
		AtomicPair(const T& first, const U& second) { set(ptr, stamp); }
		void set(const T& first, const U& second)
		{
			m_pair = Pair(first, second);
		}
		const T getFirst()
		{
			Pair pair = m_pair;
			return pair.m_first;
		}
		const U getSecond()
		{
			Pair pair = m_pair;
			return pair.m_second;
		}
		void get(T* first, U* second)
		{
			Pair pair = m_pair;
			*first = pair.m_first;
			*second = pair.m_second;
		}
		void compareAndSwap(const T& firstValue, const U& secondValue, const T& firstCompare, const U& secondCompare, T* firstResult, U* secondResult)
		{
			Pair newPair = Pair(firstValue, secondValue);
			Pair comparePair = Pair(firstCompare, secondCompare);
			Pair oldPair = m_pair.compareAndSwap(newPair, comparePair);
			*firstResult = oldPair.m_first;
			*secondResult = oldPair.m_second;
		}
		bool compareAndSwap(const T& firstValue, const U& secondValue, const T& firstCompare, const U& secondCompare)
		{
			Pair newPair = Pair(firstValue, secondValue);
			Pair comparePair = Pair(firstCompare, secondCompare);
			Pair oldPair = m_pair.compareAndSwap(newPair, comparePair);
			return (oldPair.m_first == firstCompare) && (oldPair.m_second == secondCompare);
		}
	private:
		struct Pair
		{
			Pair() { }
			Pair(const T& first, const U& second) : m_first(first), m_second(second) { }
			T m_first;
			U m_second;
		};
		Atomic<Pair> m_pair;
	};
}

#endif
